home *** CD-ROM | disk | FTP | other *** search
/ FishMarket 1.0 / FishMarket v1.0.iso / fishies / 501-525 / disk_524 / kamin / p-distr.lzh / lisp-msgc.p < prev    next >
Text File  |  1989-03-30  |  34KB  |  1,186 lines

  1. (*****************************************************************
  2.  *                     DECLARATIONS                              *
  3.  *****************************************************************)
  4. program lisp (input, output);
  5.  
  6. label 99;
  7.  
  8. const
  9.    NAMELENG = 20;      (* Maximum length of a name *)
  10.    MAXNAMES = 300;     (* Maximum number of different names *)
  11.    MAXINPUT = 4000;    (* Maximum length of an input *)
  12.    STACKSIZE = 1000;
  13.    MEMSIZE = 500;
  14.    PROMPT = '-> ';
  15.    PROMPT2 = '> ';
  16.    COMMENTCHAR = ';';
  17.    TABCODE = 9;        (* in ASCII *)
  18.  
  19. type
  20.    NAMESIZE = 0..NAMELENG;
  21.    NAMESTRING = packed array [1..NAMELENG] of char;
  22.  
  23.    NAME = 1 .. MAXNAMES; (* a NAME is an index in printNames *)
  24.  
  25.    BUILTINOP = (IFOP,WHILEOP,SETOP,BEGINOP,PLUSOP,MINUSOP,
  26.                 TIMESOP,DIVOP,EQOP,LTOP,GTOP,CONSOP,
  27.                 CAROP,CDROP,NUMBERPOP,SYMBOLPOP,
  28.                 LISTPOP,NULLPOP,PRINTOP);
  29.    VALUEOP = PLUSOP .. PRINTOP;
  30.    CONTROLOP = IFOP .. BEGINOP;
  31.  
  32.    SEXP = ^SEXPREC;
  33.    EXP = ^EXPREC;
  34.    EXPLIST = ^EXPLISTREC;
  35.    ENV = ^ENVREC;
  36.    VALUELIST = ^VALUELISTREC;
  37.    NAMELIST = ^NAMELISTREC;
  38.    FUNDEF = ^FUNDEFREC;
  39.  
  40.    SEXPTYPE = (NILSXP,NUMSXP,SYMSXP,LISTSXP);
  41.    SEXPREC = record
  42.                mark: Boolean;
  43.                case sxptype: SEXPTYPE of
  44.                   NILSXP: ();
  45.                   NUMSXP: (intval: integer);
  46.                   SYMSXP: (symval: NAME);
  47.                   LISTSXP: (carval, cdrval: SEXP)
  48.             end;
  49.  
  50.    EXPTYPE = (VALEXP,VAREXP,APEXP);
  51.    EXPREC = record
  52.                case etype: EXPTYPE of
  53.                   VALEXP: (sxp: SEXP);
  54.                   VAREXP: (varble: NAME; offset: integer); (* 0 for global *)
  55.                   APEXP: (optr: NAME; args: EXPLIST)
  56.             end;
  57.  
  58.    EXPLISTREC = record
  59.                head: EXP;
  60.                tail: EXPLIST
  61.             end;
  62.  
  63.    VALUELISTREC = record
  64.                head: SEXP;
  65.                tail: VALUELIST
  66.             end;
  67.  
  68.    NAMELISTREC = record
  69.                head: NAME;
  70.                tail: NAMELIST
  71.             end;
  72.  
  73.    ENVREC = record
  74.                vars: NAMELIST;
  75.                values: VALUELIST
  76.             end;
  77.    FUNDEFREC = record
  78.                funname: NAME;
  79.                formals: NAMELIST;
  80.                body: EXP;
  81.                nextfundef: FUNDEF
  82.             end;
  83.  
  84. var
  85.    fundefs: FUNDEF;
  86.    
  87.    globalEnv: ENV;
  88.  
  89.    argStack: array [1..STACKSIZE] of SEXP;
  90.    stacktop: integer; (* range is 1..STACKSIZE+1 *)
  91.  
  92.    memory: array [1..MEMSIZE] of SEXP;
  93.  
  94.    freeSEXP: SEXP;
  95.    
  96.    currentExp: EXP;
  97.    
  98.    userinput: array [1..MAXINPUT] of char;
  99.    inputleng, pos: 0..MAXINPUT;
  100.    
  101.    printNames: array [NAME] of NAMESTRING;
  102.    numNames, numBuiltins: NAME;
  103.  
  104.    nilValue, trueValue: SEXP;
  105.  
  106.    quittingtime: Boolean;
  107.  
  108. (*****************************************************************
  109.  *                     MEMORY MANAGEMENT                         *
  110.  *****************************************************************)
  111.  
  112. (* initMemory - initialize memory                                *)
  113. procedure initMemory;
  114. var i: integer;
  115. begin
  116.    for i:=1 to MEMSIZE do new(memory[i]);
  117.    for i:=1 to MEMSIZE-1 do memory[i]^.carval := memory[i+1];
  118.    memory[MEMSIZE]^.carval := nil;
  119.    freeSEXP := memory[1]
  120. end; (* initMemory *)
  121.  
  122. procedure gc; forward;
  123.  
  124. (* allocSExp - get SEXPREC from free list; call gc if necessary  *)
  125. function allocSExp (t: SEXPTYPE): SEXP;
  126. var s: SEXP;
  127. begin
  128.    if freeSEXP = nil
  129.    then begin
  130.            gc;
  131.            if freeSEXP = nil (* garbage collection didn't help *)
  132.            then begin
  133.                    writeln('Memory overflow');
  134.                    goto 99
  135.                 end;
  136.            if currentExp = nil
  137.            then begin
  138.                    writeln('Called gc during parsing. ',
  139.                            'Parse aborted; reenter input');
  140.                    goto 99
  141.                 end
  142.         end;
  143.    s := freeSEXP;
  144.    freeSEXP := s^.carval;
  145.    s^.sxptype := t;
  146.    allocSExp := s
  147. end; (* allocSExp *)
  148.  
  149. (* gc - mark-scan garbage collector                              *)
  150. procedure gc;
  151.  
  152. var collected: integer;
  153.  
  154. (* unmarkPhase - reset mark in ALL cons cells                    *)
  155.    procedure unmarkPhase;
  156.    var i: integer;
  157.    begin
  158.       for i := 1 to MEMSIZE do memory[i]^.mark := false
  159.    end; (* unmarkPhase *)
  160.  
  161. (* markPhase - set mark in all accessible cons cells             *)
  162.    procedure markPhase;
  163.    var
  164.       i: integer;
  165.       fd: FUNDEF;
  166.  
  167. (* markSExp - set mark in s and all cells accessible from it     *)
  168.       procedure markSExp (s: SEXP);
  169.       begin
  170.          if not s^.mark
  171.          then begin
  172.                  s^.mark := true;
  173.                  if s^.sxptype = LISTSXP
  174.                  then begin
  175.                          markSExp(s^.carval);
  176.                          markSExp(s^.cdrval)
  177.                       end
  178.               end
  179.       end; (* markSExp *)
  180.  
  181. (* markValuelist - set mark in all cells accessible from vl      *)
  182.       procedure markValuelist (vl: VALUELIST);
  183.       begin
  184.          while vl <> nil do begin
  185.             markSExp(vl^.head);
  186.             vl := vl^.tail
  187.             end
  188.       end; (* markValuelist *)
  189.  
  190. (* markEnv - set mark in all cells accessible from rho           *)
  191.       procedure markEnv (rho: ENV);
  192.       begin
  193.          markValuelist(rho^.values)
  194.       end; (* markEnv *)
  195.  
  196. (* markExp - set mark in all cells accessible from e             *)
  197.       procedure markExp (e: EXP);
  198.  
  199. (* markExplist - set mark in all cells accessible from el        *)
  200.          procedure markExplist (el: EXPLIST);
  201.          begin
  202.             while el <> nil do begin
  203.                markExp(el^.head);
  204.                el := el^.tail
  205.                end
  206.          end; (* markExplist *)
  207.  
  208.       begin (* markExp *)
  209.          case e^.etype of
  210.            VALEXP: markSExp(e^.sxp);
  211.            VAREXP: ;
  212.            APEXP: markExplist(e^.args)
  213.          end
  214.       end; (* markExp *)
  215.  
  216.    begin (* markPhase *)
  217.       markSExp(nilValue);
  218.       markSExp(trueValue);
  219.       markEnv(globalEnv);
  220.       if currentExp <> nil then markExp(currentExp);
  221.       fd := fundefs;
  222.       while fd <> nil do begin
  223.          markExp(fd^.body);
  224.          fd := fd^.nextfundef
  225.          end;
  226.       for i:=1 to stacktop-1 do markSExp (argStack[i])
  227.    end; (* markPhase *)
  228.  
  229. (* scanPhase - reconstruct free list from cells not marked       *)
  230.    procedure scanPhase;
  231.    var i: integer;
  232.    begin
  233.       freeSEXP := nil;
  234.       collected := 0;
  235.       for i := 1 to MEMSIZE do
  236.         if not memory[i]^.mark (* memory[i] inaccessible *)
  237.         then begin
  238.                 memory[i]^.carval := freeSEXP;
  239.                 freeSEXP := memory[i];
  240.                 collected := collected+1
  241.              end
  242.    end; (* scanPhase *)
  243.  
  244. begin (* gc *)
  245.    write('Garbage collection ...');
  246.    unmarkPhase;
  247.    markPhase;
  248.    scanPhase;
  249.    writeln('collected ', collected:1,
  250.          '(',round(100*collected/MEMSIZE):1,'%) records')
  251. end; (* gc *)
  252.  
  253. (* initStack - initialize environment stack                      *)
  254. procedure initStack;
  255. begin
  256.    stacktop := 1
  257. end; (* initStack *)
  258.  
  259. (* pushArg - push a single argument onto argStack                *)
  260. procedure pushArg (s: SEXP);
  261. begin
  262.    if stacktop > STACKSIZE
  263.    then begin
  264.            writeln('Stack overflow');
  265.            stacktop := 1;
  266.            goto 99
  267.         end;
  268.    argStack[stacktop] := s;
  269.    stacktop := stacktop + 1
  270. end; (* pushArg *)
  271.  
  272. (* topArg - return top item in stack                             *)
  273. function topArg: SEXP;
  274. begin
  275.    topArg := argStack[stacktop-1]
  276. end; (* topArg *)
  277.  
  278. (* popArgs - pop argument list from top of argStack              *)
  279. procedure popArgs (l: integer);
  280. begin
  281.    stacktop := stacktop - l
  282. end; (* popArgs *)
  283.  
  284. (*****************************************************************
  285.  *                     DATA STRUCTURE OP'S                       *
  286.  *****************************************************************)
  287.  
  288. (* mkVALEXP - return an EXP of type VALEXP with sxp s            *)
  289. function mkVALEXP (s: SEXP): EXP;
  290. var e: EXP;
  291. begin
  292.    new(e);
  293.    e^.etype := VALEXP;
  294.    e^.sxp := s;
  295.    mkVALEXP := e
  296. end; (* mkVALEXP *)
  297.  
  298. (* mkVAREXP - return an EXP of type VAREXP with varble nm        *)
  299. function mkVAREXP (nm: NAME): EXP;
  300. var e: EXP;
  301. begin
  302.    new(e);
  303.    e^.etype := VAREXP;
  304.    e^.varble := nm;
  305.    e^.offset := 0;
  306.    mkVAREXP := e
  307. end; (* mkVAREXP *)
  308.  
  309. (* mkAPEXP - return EXP of type APEXP w/ optr op and args el     *)
  310. function mkAPEXP (op: NAME; el: EXPLIST): EXP;
  311. var e: EXP;
  312. begin
  313.    new(e);
  314.    e^.etype := APEXP;
  315.    e^.optr := op;
  316.    e^.args := el;
  317.    mkAPEXP := e
  318. end; (* mkAPEXP *)
  319.  
  320. (* mkExplist - return an EXPLIST with head e and tail el         *)
  321. function mkExplist (e: EXP; el: EXPLIST): EXPLIST;
  322. var newel: EXPLIST;
  323. begin
  324.    new(newel);
  325.    newel^.head := e;
  326.    newel^.tail := el;
  327.    mkExplist := newel
  328. end; (* mkExplist *)
  329.  
  330. (* mkNamelist - return a NAMELIST with head n and tail nl        *)
  331. function mkNamelist (nm: NAME; nl: NAMELIST): NAMELIST;
  332. var newnl: NAMELIST;
  333. begin
  334.    new(newnl);
  335.    newnl^.head := nm;
  336.    newnl^.tail := nl;
  337.    mkNamelist := newnl
  338. end; (* mkNamelist *)
  339.  
  340. (* mkValuelist - return an VALUELIST with head s and tail vl     *)
  341. function mkValuelist (s: SEXP; vl: VALUELIST): VALUELIST;
  342. var newvl: VALUELIST;
  343. begin
  344.    new(newvl);
  345.    newvl^.head := s;
  346.    newvl^.tail := vl;
  347.    mkValuelist := newvl
  348. end; (* mkValuelist *)
  349.  
  350. (* mkEnv - return an ENV with vars nl and values vl              *)
  351. function mkEnv (nl: NAMELIST; vl: VALUELIST): ENV;
  352. var rho: ENV;
  353. begin
  354.    new(rho);
  355.    rho^.vars := nl;
  356.    rho^.values := vl;
  357.    mkEnv := rho
  358. end; (* mkEnv *)
  359.  
  360. (* lengthNL - return length of NAMELIST nl                       *)
  361. function lengthNL (nl: NAMELIST): integer;
  362. var i: integer;
  363. begin
  364.    i := 0;
  365.    while nl <> nil do begin
  366.       i := i+1;
  367.       nl := nl^.tail
  368.       end;
  369.    lengthNL := i
  370. end; (* lengthNL *)
  371.  
  372. (*****************************************************************
  373.  *                     NAME MANAGEMENT                           *
  374.  *****************************************************************)
  375.  
  376. (* fetchFun - get function definition of fname from fundefs      *)
  377. function fetchFun (fname: NAME): FUNDEF;
  378. var
  379.    f: FUNDEF;
  380.    found: Boolean;
  381. begin
  382.    found := false;
  383.    f := fundefs;
  384.    while (f <> nil) and not found do
  385.       if f^.funname = fname
  386.       then found := true
  387.       else f := f^.nextfundef;
  388.    fetchFun := f
  389. end; (* fetchFun *)
  390.  
  391. (* newFunDef - add new function fname w/ parameters nl, body e   *)
  392. procedure newFunDef (fname: NAME; nl: NAMELIST; e: EXP);
  393. var f: FUNDEF;
  394. begin
  395.    f := fetchFun(fname);
  396.    if f = nil (* fname not yet defined as a function *)
  397.    then begin
  398.            new(f);
  399.            f^.nextfundef := fundefs; (* place new FUNDEFREC *)
  400.            fundefs := f              (* on fundefs list *)
  401.         end;
  402.    f^.funname := fname;
  403.    f^.formals := nl;
  404.    f^.body := e
  405. end; (* newFunDef *)
  406.  
  407. (* initNames - place all pre-defined names into printNames       *)
  408. procedure initNames;
  409. var i: integer;
  410. begin
  411.    fundefs := nil;
  412.    i := 1;
  413.    printNames[i] := 'if                  '; i := i+1;
  414.    printNames[i] := 'while               '; i := i+1;
  415.    printNames[i] := 'set                 '; i := i+1;
  416.    printNames[i] := 'begin               '; i := i+1;
  417.    printNames[i] := '+                   '; i := i+1;
  418.    printNames[i] := '-                   '; i := i+1;
  419.    printNames[i] := '*                   '; i := i+1;
  420.    printNames[i] := '/                   '; i := i+1;
  421.    printNames[i] := '=                   '; i := i+1;
  422.    printNames[i] := '<                   '; i := i+1;
  423.    printNames[i] := '>                   '; i := i+1;
  424.    printNames[i] := 'cons                '; i := i+1;
  425.    printNames[i] := 'car                 '; i := i+1;
  426.    printNames[i] := 'cdr                 '; i := i+1;
  427.    printNames[i] := 'number?             '; i := i+1;
  428.    printNames[i] := 'symbol?             '; i := i+1;
  429.    printNames[i] := 'list?               '; i := i+1;
  430.    printNames[i] := 'null?               '; i := i+1;
  431.    printNames[i] := 'print               '; i := i+1;
  432.    printNames[i] := 'T                   ';
  433.    numNames := i;
  434.    numBuiltins := i
  435. end; (* initNames *)
  436.  
  437. (* install - insert new name into printNames                     *)
  438. function install (nm: NAMESTRING): NAME;
  439. var
  440.    i: integer;
  441.    found: Boolean;
  442. begin
  443.    i := 1; found := false;
  444.    while (i <= numNames) and not found
  445.    do if nm = printNames[i]
  446.       then found := true
  447.       else i := i+1;
  448.    if not found
  449.    then begin
  450.            if i > MAXNAMES
  451.            then begin
  452.                    writeln('No more room for names');
  453.                    goto 99
  454.                 end;
  455.            numNames := i;
  456.            printNames[i] := nm
  457.         end;
  458.    install := i
  459. end; (* install *)
  460.  
  461. (* prName - print name nm                                        *)
  462. procedure prName (nm: NAME);
  463. var i: integer;
  464. begin
  465.    i := 1;
  466.    while i <= NAMELENG
  467.    do if printNames[nm][i] <> ' '
  468.       then begin
  469.               write(printNames[nm][i]);
  470.               i := i+1
  471.            end
  472.       else i := NAMELENG+1
  473. end; (* prName *)
  474.  
  475. (* primOp - translate NAME optr to corresponding BUILTINOP       *)
  476. function primOp (optr: NAME): BUILTINOP;
  477. var
  478.    op: BUILTINOP;
  479.    i: integer;
  480. begin
  481.    op := IFOP; (* N.B. IFOP is first value in BUILTINOPS *)
  482.    for i := 1 to optr-1 do op := succ(op);
  483.    primOp := op
  484. end; (* primOp *)
  485.  
  486. (*****************************************************************
  487.  *                        INPUT                                  *
  488.  *****************************************************************)
  489.  
  490. (* isDelim - check if c is a delimiter                           *)
  491. function isDelim (c: char): Boolean;
  492. begin
  493.    isDelim := c in ['(', ')', ' ', COMMENTCHAR]
  494. end; (* isDelim *)
  495.  
  496. (* skipblanks - return next non-blank position in userinput      *)
  497. function skipblanks (p: integer): integer;
  498. begin
  499.    while userinput[p] = ' ' do p := p+1;
  500.    skipblanks := p
  501. end; (* skipblanks *)
  502.  
  503. (* matches - check if string nm matches userinput[s .. s+leng]   *)
  504. function matches (s: integer; leng: NAMESIZE;
  505.                    nm: NAMESTRING): Boolean;
  506. var
  507.    match: Boolean;
  508.    i: integer;
  509. begin
  510.    match := true; i := 1;
  511.    while match and (i <= leng) do begin
  512.       if userinput[s] <> nm[i] then match := false;
  513.       i := i+1;
  514.       s := s+1
  515.       end;
  516.    if not isDelim(userinput[s]) then match := false;
  517.    matches := match
  518. end; (* matches *)
  519.  
  520. (* reader - read char's into userinput; be sure input not blank  *)
  521. procedure reader;
  522.  
  523. (* readInput - read char's into userinput                        *)
  524.    procedure readInput;
  525.  
  526.    var c: char;
  527.  
  528. (* nextchar - read next char - filter tabs and comments          *)
  529.       procedure nextchar (var c: char);
  530.       begin
  531.          read(c);
  532.          if c = chr(TABCODE)
  533.          then c := ' '
  534.          else if c = COMMENTCHAR
  535.               then begin while not eoln do read(c); c := ' ' end
  536.       end; (* nextchar *)
  537.  
  538. (* readParens - read char's, ignoring newlines, to matching ')'  *)
  539.       procedure readParens;
  540.       var
  541.          parencnt: integer; (* current depth of parentheses *)
  542.          c: char;
  543.       begin
  544.          parencnt := 1; (* '(' just read *)
  545.          repeat
  546.             if eoln then write(PROMPT2);
  547.             nextchar(c);
  548.             pos := pos+1;
  549.             if pos = MAXINPUT
  550.             then begin
  551.                     writeln('User input too long');
  552.                     goto 99
  553.                  end;
  554.             userinput[pos] := c;
  555.             if c = '(' then parencnt := parencnt+1;
  556.             if c = ')' then parencnt := parencnt-1
  557.          until parencnt = 0
  558.       end; (* readParens *)
  559.  
  560.    begin (* readInput *)
  561.       write(PROMPT);
  562.       pos := 0;
  563.       repeat
  564.          pos := pos+1;
  565.          if pos = MAXINPUT
  566.          then begin
  567.                  writeln('User input too long');
  568.                  goto 99
  569.               end;
  570.          nextchar(c);
  571.          userinput[pos] := c;
  572.          if userinput[pos] = '(' then readParens
  573.       until eoln;
  574.       inputleng := pos;
  575.       userinput[pos+1] := COMMENTCHAR (* sentinel *)
  576.    end; (* readInput *)
  577.  
  578. begin (* reader *)
  579.     repeat
  580.        readInput;
  581.        pos := skipblanks(1);
  582.     until pos <= inputleng (* ignore blank lines *)
  583. end; (* reader *)
  584.  
  585. (* parseName - return (installed) NAME starting at userinput[pos]*)
  586. function parseName: NAME;
  587. var
  588.    nm: NAMESTRING; (* array to accumulate characters *)
  589.    leng: NAMESIZE; (* length of name *)
  590. begin
  591.    leng := 0;
  592.    while (pos <= inputleng) and not isDelim(userinput[pos])
  593.    do begin
  594.          if leng = NAMELENG
  595.          then begin
  596.                  writeln('Name too long, begins: ', nm);
  597.                  goto 99
  598.               end;
  599.          leng := leng+1;
  600.          nm[leng] := userinput[pos];
  601.          pos := pos+1
  602.       end;
  603.    if leng = 0
  604.    then begin
  605.            writeln('Error: expected name, instead read: ',
  606.                    userinput[pos]);
  607.            goto 99
  608.         end;
  609.    for leng := leng+1 to NAMELENG do nm[leng] := ' ';
  610.    pos := skipblanks(pos); (* skip blanks after name *)
  611.    parseName := install(nm)
  612. end; (* parseName *)
  613.  
  614. (* isNumber - check if a number begins at pos                    *)
  615. function isNumber (pos: integer): Boolean;
  616.  
  617. (* isDigits - check if sequence of digits begins at pos          *)
  618.    function isDigits (pos: integer): Boolean;
  619.    begin
  620.       if not (userinput[pos] in ['0'..'9'])
  621.       then isDigits := false
  622.       else begin
  623.               isDigits := true;
  624.               while userinput[pos] in ['0'..'9'] do pos := pos+1;
  625.               if not isDelim(userinput[pos])
  626.               then isDigits := false
  627.            end
  628.    end; (* isDigits *)
  629.  
  630. begin (* isNumber *)
  631.    isNumber := isDigits(pos) or
  632.               ((userinput[pos] = '-') and isDigits(pos+1))
  633. end; (* isNumber *)
  634.  
  635. (* isValue - check if a number or quoted const begins at pos     *)
  636. function isValue (pos: integer): Boolean;
  637. begin
  638.    isValue:= (userinput[pos] = '''') or isNumber(pos)
  639. end; (* isValue *)
  640.  
  641. (* parseVal - return S-expression starting at userinput[pos]     *)
  642. function parseVal: SEXP;
  643.  
  644. (* parseSExp - return quoted S-expr starting at userinput[pos]   *)
  645.    function parseSExp: SEXP;
  646.  
  647.    var s: SEXP;
  648.  
  649. (* parseInt - return number starting at userinput[pos]           *)
  650.       function parseInt: SEXP;
  651.       var sum, sign: integer;
  652.       begin
  653.          s := allocSExp(NUMSXP);
  654.          sum := 0; sign := 1;
  655.          if userinput[pos] = '-'
  656.          then begin
  657.                  sign := -1;
  658.                  pos := pos+1
  659.               end;
  660.          while userinput[pos] in ['0'..'9'] do begin
  661.             sum := 10*sum + (ord(userinput[pos]) - ord('0'));
  662.             pos := pos+1
  663.             end;
  664.          s^.intval := sum * sign;
  665.          pos := skipblanks(pos); (* skip blanks after number *)
  666.          parseInt := s
  667.       end; (* parseInt *)
  668.  
  669. (* parseSym - return symbol starting at userinput[pos]           *)
  670.       function parseSym: SEXP;
  671.       begin
  672.          s := allocSExp(SYMSXP);
  673.          s^.symval := parseName;
  674.          parseSym := s
  675.       end; (* parseSym *)
  676.  
  677. (* parseList - return list starting at userinput[pos]            *)
  678.       function parseList: SEXP;
  679.       var car, cdr: SEXP;
  680.       begin
  681.          if userinput[pos] = ')'
  682.          then begin
  683.                  parseList := allocSExp(NILSXP);
  684.                  pos := skipblanks(pos+1)
  685.               end
  686.          else begin
  687.                  car := parseSExp;
  688.                  cdr := parseList;
  689.                  s := allocSExp(LISTSXP);
  690.                  s^.carval := car;
  691.                  s^.cdrval := cdr;
  692.                  parseList := s
  693.               end
  694.       end; (* parseList *)
  695.  
  696.    begin (* parseSExp *)
  697.       if isNumber(pos)
  698.       then parseSExp := parseInt
  699.       else if userinput[pos] = '('
  700.            then begin
  701.                    pos := skipblanks(pos+1);
  702.                    parseSExp := parseList
  703.                 end
  704.            else parseSExp := parseSym
  705.    end; (* parseSExp *)
  706.  
  707. begin (* parseVal *)
  708.    if userinput[pos] = '''' then pos := pos+1;
  709.    parseVal := parseSExp
  710. end; (* parseVal *)
  711.  
  712. function parseEL: EXPLIST; forward;
  713.  
  714. (* parseExp - return EXP starting at userinput[pos]              *)
  715. function parseExp: EXP;
  716. var
  717.    nm: NAME;
  718.    el: EXPLIST;
  719. begin
  720.    if userinput[pos] = '('
  721.    then begin   (* APEXP *)
  722.            pos := skipblanks(pos+1); (* skip '( ..' *)
  723.            nm := parseName;
  724.            el := parseEL;
  725.            parseExp := mkAPEXP(nm, el)
  726.         end
  727.    else if isValue(pos)
  728.         then parseExp := mkVALEXP(parseVal)   (* VALEXP *)
  729.         else parseExp := mkVAREXP(parseName)  (* VAREXP *)
  730. end; (* parseExp *)
  731.  
  732. (* parseEL - return EXPLIST starting at userinput[pos]           *)
  733. function parseEL;
  734. var
  735.    e: EXP;
  736.    el: EXPLIST;
  737. begin
  738.    if userinput[pos] = ')'
  739.    then begin
  740.            pos := skipblanks(pos+1); (* skip ') ..' *)
  741.            parseEL := nil
  742.         end
  743.    else begin
  744.            e := parseExp;
  745.            el := parseEL;
  746.            parseEL := mkExplist(e, el)
  747.         end
  748. end; (* parseEL *)
  749.  
  750. (* parseNL - return NAMELIST starting at userinput[pos]          *)
  751. function parseNL: NAMELIST;
  752. var
  753.    nm: NAME;
  754.    nl: NAMELIST;
  755. begin
  756.    if userinput[pos] = ')'
  757.    then begin
  758.            pos := skipblanks(pos+1); (* skip ') ..' *)
  759.            parseNL := nil
  760.         end
  761.    else begin
  762.            nm := parseName;
  763.            nl := parseNL;
  764.            parseNL := mkNamelist(nm, nl)
  765.         end
  766. end; (* parseNL *)
  767.  
  768. (* parseDef - parse function definition at userinput[pos]        *)
  769. function parseDef: NAME;
  770. var
  771.    fname: NAME;        (* function name *)
  772.    nl: NAMELIST;       (* formal parameters *)
  773.    e: EXP;             (* body *)
  774.  
  775. (* processExpVars - insert offsets in all VAREXP's within e      *)
  776.    procedure processExpVars (e: EXP);
  777.  
  778. (* offsetOfVar - return location of nm in nl, or zero            *)
  779.       function offsetOfVar (nm: NAME; nl: NAMELIST): integer;
  780.       var
  781.          i: integer;
  782.          found: Boolean;
  783.       begin
  784.          i := 1; found := false;
  785.          while (nl <> nil) and not found do
  786.             if nm = nl^.head
  787.             then found := true
  788.             else begin
  789.                     i := i+1;
  790.                     nl := nl^.tail
  791.                  end;
  792.          if not found then i := 0;
  793.          offsetOfVar := i
  794.       end; (* offsetOfVar *)
  795.  
  796. (* processELVars - apply processExpVars to each expression in el *)
  797.       procedure processELVars (el: EXPLIST);
  798.       begin
  799.          while el <> nil do begin
  800.             processExpVars(el^.head);
  801.             el := el^.tail
  802.             end
  803.       end; (* processELVars *)
  804.  
  805.    begin (* processExpVars *)
  806.       with e^ do
  807.          case etype of
  808.             VALEXP: ;
  809.             VAREXP: offset := offsetOfVar(varble, nl);
  810.             APEXP: processELVars(args)
  811.          end
  812.    end; (* processExpVars *)
  813.  
  814. begin (* parseDef *)
  815.    pos := skipblanks(pos+1); (* skip '( ..' *)
  816.    pos := skipblanks(pos+6); (* skip 'define ..' *)
  817.    fname := parseName;
  818.    pos := skipblanks(pos+1); (* skip '( ..' *)
  819.    nl := parseNL;
  820.    e := parseExp;
  821.    pos := skipblanks(pos+1); (* skip ') ..' *)
  822.    newFunDef(fname, nl, e);
  823.    processExpVars(e);
  824.    parseDef := fname
  825. end; (* parseDef *)
  826.  
  827. (*****************************************************************
  828.  *                     ENVIRONMENTS                              *
  829.  *****************************************************************)
  830.  
  831. (* emptyEnv - return an environment with no bindings             *)
  832. function emptyEnv: ENV;
  833. begin
  834.    emptyEnv := mkEnv(nil, nil)
  835. end; (* emptyEnv *)
  836.  
  837. (* bindVar - bind variable nm to value s in environment rho      *)
  838. procedure bindVar (nm: NAME; s: SEXP; rho: ENV);
  839. begin
  840.    rho^.vars := mkNamelist(nm, rho^.vars);
  841.    rho^.values := mkValuelist(s, rho^.values)
  842. end; (* bindVar *)
  843.  
  844. (* findVar - look up nm in rho                                   *)
  845. function findVar (nm: NAME; rho: ENV): VALUELIST;
  846. var
  847.    nl: NAMELIST;
  848.    vl: VALUELIST;
  849.    found: Boolean;
  850. begin
  851.    found := false;
  852.    nl := rho^.vars;
  853.    vl := rho^.values;
  854.    while (nl <> nil) and not found do
  855.       if nl^.head = nm
  856.       then found := true
  857.       else begin
  858.               nl := nl^.tail;
  859.               vl := vl^.tail
  860.            end;
  861.    findVar := vl
  862. end; (* findVar *)
  863.  
  864. (* assign - assign value s to variable nm in rho                 *)
  865. procedure assign (nm: NAME; s: SEXP; rho: ENV);
  866. var varloc: VALUELIST;
  867. begin
  868.    varloc := findVar(nm, rho);
  869.    varloc^.head := s
  870. end; (* assign *)
  871.  
  872. (* fetch - return SEXP bound to nm in rho                        *)
  873. function fetch (nm: NAME; rho: ENV): SEXP;
  874. var vl: VALUELIST;
  875. begin
  876.    vl := findVar(nm, rho);
  877.    fetch := vl^.head
  878. end; (* fetch *)
  879.  
  880. (* isBound - check if nm is bound in rho                         *)
  881. function isBound (nm: NAME; rho: ENV): Boolean;
  882. begin
  883.    isBound := findVar(nm, rho) <> nil
  884. end; (* isBound *)
  885. (*****************************************************************
  886.  *                     S-EXPRESSIONS                             *
  887.  *****************************************************************)
  888.  
  889. (* prValue - print S-expression s                                *)
  890. procedure prValue (s: SEXP);
  891. var s1: SEXP;
  892. begin
  893.    with s^ do
  894.       case sxptype of
  895.          NILSXP: write('()');
  896.          NUMSXP: write(intval:1);
  897.          SYMSXP: prName(symval);
  898.          LISTSXP:
  899.             begin
  900.                write('(');
  901.                prValue(carval);
  902.                s1 := cdrval;
  903.                while s1^.sxptype = LISTSXP do begin
  904.                   write(' ');
  905.                   prValue(s1^.carval);
  906.                   s1 := s1^.cdrval
  907.                   end;
  908.                write(')')
  909.             end
  910.       end (* case and with *)
  911. end; (* prValue *)
  912.  
  913. (* isTrueVal - return true if s is true (non-NIL) value          *)
  914. function isTrueVal (s: SEXP): Boolean;
  915. begin
  916.    isTrueVal := s^.sxptype <> NILSXP
  917. end; (* isTrueVal *)
  918.  
  919. (* applyValueOp - apply VALUEOP op to arguments on top of stack  *)
  920. function applyValueOp (op: VALUEOP): SEXP;
  921.  
  922. var
  923.    result: SEXP;
  924.    s1, s2: SEXP;
  925.  
  926. (* applyArithOp - apply binary, arithmetic VALUEOP to arguments  *)
  927.    procedure applyArithOp (n1, n2: integer);
  928.    begin
  929.       with result^ do
  930.          case op of
  931.             PLUSOP: intval := n1+n2;
  932.             MINUSOP: intval := n1-n2;
  933.             TIMESOP: intval := n1*n2;
  934.             DIVOP: intval := n1 div n2
  935.          end
  936.    end; (* applyArithOp *)
  937.  
  938. (* applyRelOp - apply binary, relational VALUEOP to arguments    *)
  939.    procedure applyRelOp (n1, n2: integer) ;
  940.    begin
  941.       case op of
  942.          LTOP: if n1 < n2 then result := trueValue;
  943.          GTOP: if n1 > n2 then result := trueValue
  944.       end
  945.    end; (* applyRelOp *)
  946.  
  947. (* arity - return number of arguments expected by op             *)
  948.    function arity (op: VALUEOP): integer;
  949.    begin
  950.       if op in [PLUSOP .. CONSOP] then arity := 2 else arity := 1
  951.    end; (* arity *)
  952.  
  953. begin (* applyValueOp *)
  954.    result := nilValue;
  955.    if op in [PLUSOP .. DIVOP]
  956.    then result := allocSExp(NUMSXP)
  957.    else if op = CONSOP
  958.         then result := allocSExp(LISTSXP);
  959.    s1 := topArg; (* 1st actual *)
  960.    popArgs(1);
  961.    if arity(op) = 2
  962.    then begin
  963.            s2 := s1; (* 1st actual was really 2nd actual *)
  964.            s1 := topArg; (* 1st actual *)
  965.            popArgs(1)
  966.         end;
  967.    if op in [PLUSOP .. DIVOP, LTOP .. GTOP]
  968.    then if (s1^.sxptype = NUMSXP)
  969.            and (s2^.sxptype = NUMSXP)
  970.         then if op in [PLUSOP .. DIVOP]
  971.              then applyArithOp(s1^.intval, s2^.intval)
  972.              else applyRelOp(s1^.intval, s2^.intval)
  973.         else begin
  974.                 write('Non-arithmetic arguments to ');
  975.                 prName(ord(op)+1);
  976.                 writeln;
  977.                 goto 99
  978.              end
  979.    else with s1^ do
  980.            case op of
  981.               EQOP:
  982.                  if (sxptype = NILSXP)
  983.                     and (s2^.sxptype = NILSXP)
  984.                  then result := trueValue
  985.                  else if (sxptype = NUMSXP)
  986.                          and (s2^.sxptype = NUMSXP)
  987.                          and (intval = s2^.intval)
  988.                       then result := trueValue
  989.                       else if (sxptype = SYMSXP)
  990.                               and (s2^.sxptype = SYMSXP)
  991.                               and (symval = s2^.symval)
  992.                            then result := trueValue;
  993.               CONSOP:
  994.                  with result^ do begin
  995.                     carval := s1;
  996.                     cdrval := s2
  997.                     end;
  998.               CAROP:
  999.                  if sxptype <> LISTSXP
  1000.                  then begin
  1001.                          write('Error: car applied to non-list: ');
  1002.                          prValue(s1);
  1003.                          writeln
  1004.                       end
  1005.                  else result := carval;
  1006.               CDROP:
  1007.                  if sxptype <> LISTSXP
  1008.                  then begin
  1009.                          write('Error: cdr applied to non-list: ');
  1010.                          prValue(s1);
  1011.                          writeln
  1012.                       end
  1013.                  else result := cdrval;
  1014.               NUMBERPOP:
  1015.                  if sxptype = NUMSXP then result := trueValue;
  1016.               SYMBOLPOP:
  1017.                  if sxptype = SYMSXP then result := trueValue;
  1018.               LISTPOP:
  1019.                  if sxptype = LISTSXP then result := trueValue;
  1020.               NULLPOP:
  1021.                  if sxptype = NILSXP then result := trueValue;
  1022.               PRINTOP:
  1023.                  begin prValue(s1); writeln; result := s1 end
  1024.            end; (* case and with *)
  1025.    applyValueOp := result
  1026. end; (* applyValueOp *)
  1027.  
  1028. (*****************************************************************
  1029.  *                     EVALUATION                                *
  1030.  *****************************************************************)
  1031.  
  1032. (* eval - return value of e; param's start at argStack[AR]       *)
  1033. function eval (e: EXP; AR: integer): SEXP;
  1034.  
  1035. var
  1036.    op: BUILTINOP;
  1037.    newAR: integer;
  1038.  
  1039. (* evalList - evaluate each expression in el                     *)
  1040.    procedure evalList (el: EXPLIST);
  1041.    var h: SEXP;
  1042.    begin
  1043.       if el <> nil
  1044.       then begin
  1045.               h := eval(el^.head, AR);
  1046.               pushArg(h);
  1047.               evalList(el^.tail)
  1048.            end
  1049.    end; (* evalList *)
  1050.  
  1051. (* applyUserFun - apply nm; arg's start at argStack[newAR]       *)
  1052.    function applyUserFun (nm: NAME; newAR: integer): SEXP;
  1053.    var f: FUNDEF;
  1054.    begin
  1055.       f := fetchFun(nm);
  1056.       if f = nil
  1057.       then begin
  1058.               write('Undefined function: ');
  1059.               prName(nm);
  1060.               writeln;
  1061.               goto 99
  1062.            end;
  1063.       with f^ do begin
  1064.          applyUserFun := eval(body, newAR);
  1065.          popArgs(lengthNL(formals))
  1066.          end
  1067.    end; (* applyUserFun *)
  1068.  
  1069. (* applyCtrlOp - apply CONTROLOP op to args                      *)
  1070.    function applyCtrlOp (op: CONTROLOP;
  1071.                        args: EXPLIST): SEXP;
  1072.    var s: SEXP;
  1073.    begin
  1074.       with args^ do
  1075.          case op of
  1076.            IFOP:
  1077.               if isTrueVal(eval(head, AR))
  1078.               then applyCtrlOp := eval(tail^.head, AR)
  1079.               else applyCtrlOp := eval(tail^.tail^.head, AR);
  1080.            WHILEOP:
  1081.               begin
  1082.                  s := eval(head, AR);
  1083.                  while isTrueVal(s)
  1084.                  do begin
  1085.                        s := eval(tail^.head, AR);
  1086.                        s := eval(head, AR)
  1087.                     end;
  1088.                  applyCtrlOp := s
  1089.               end;
  1090.            SETOP:
  1091.               begin
  1092.                  s := eval(tail^.head, AR);
  1093.                  if head^.offset>0
  1094.                  then argStack[AR+head^.offset-1] := s
  1095.                  else if isBound(head^.varble, globalEnv)
  1096.                       then assign(head^.varble, s, globalEnv)
  1097.                       else bindVar(head^.varble, s, globalEnv);
  1098.                  applyCtrlOp := s
  1099.               end;
  1100.            BEGINOP: 
  1101.               begin
  1102.                  while args^.tail <> nil do
  1103.                     begin
  1104.                        s := eval(args^.head, AR);
  1105.                        args := args^.tail
  1106.                     end;
  1107.                  applyCtrlOp := eval(args^.head, AR)
  1108.               end
  1109.          end (* case and with *)
  1110.    end; (* applyCtrlOp *)
  1111.  
  1112. begin (* eval *)
  1113.    with e^ do
  1114.       case etype of
  1115.          VALEXP:
  1116.             eval := sxp;
  1117.          VAREXP:
  1118.             if offset > 0
  1119.             then eval := argStack[AR+offset-1]
  1120.             else if isBound(varble, globalEnv)
  1121.                  then eval := fetch(varble, globalEnv)
  1122.                  else begin
  1123.                          write('Undefined variable: ');
  1124.                          prName(varble);
  1125.                          writeln;
  1126.                          goto 99
  1127.                       end;
  1128.          APEXP: 
  1129.             if optr > numBuiltins
  1130.             then begin
  1131.                     newAR := stacktop;
  1132.                     evalList(args);
  1133.                     eval := applyUserFun(optr, newAR)
  1134.                  end
  1135.             else begin
  1136.                     op := primOp(optr);
  1137.                     if op in [IFOP .. BEGINOP]
  1138.                     then eval := applyCtrlOp(op, args)
  1139.                     else begin
  1140.                             evalList(args);
  1141.                             eval := applyValueOp(op)
  1142.                          end
  1143.                  end
  1144.       end (* case and with *)
  1145. end; (* eval *)
  1146.  
  1147. (*****************************************************************
  1148.  *                     READ-EVAL-PRINT LOOP                      *
  1149.  *****************************************************************)
  1150.  
  1151. begin (* lisp main *)
  1152.    initNames;
  1153.    initMemory;
  1154.  
  1155.    nilValue := allocSExp(NILSXP);
  1156.    trueValue := allocSExp(SYMSXP); trueValue^.symval := numNames;
  1157.  
  1158.    globalEnv := emptyEnv;
  1159.  
  1160.    quittingtime := false;
  1161. 99:
  1162.    while not quittingtime do begin
  1163.       reader;
  1164.       if matches(pos, 4, 'quit                ')
  1165.       then quittingtime := true
  1166.       else if (userinput[pos] = '(') and
  1167.               matches(skipblanks(pos+1), 6, 'define              ')
  1168.            then begin
  1169.                    currentExp := nil;
  1170.                    prName(parseDef);
  1171.                    writeln
  1172.                 end
  1173.            else begin
  1174.                    currentExp := nil;
  1175.                    currentExp := parseExp;
  1176.                    initStack;
  1177.                    prValue(eval(currentExp, 0));
  1178.                    writeln;
  1179.                    writeln
  1180.                 end
  1181.       end (* while *)
  1182. end. (* lisp *)
  1183.    
  1184.  
  1185.  
  1186.